#include "Util.h"

int              Util::rc  = -1;
zlog_category_t *Util::log = NULL;

std::shared_ptr<Util> Util::util = nullptr;

bool directory_exists(const char *path) {
    struct stat buffer;
    return (stat(path, &buffer) == 0 && S_ISDIR(buffer.st_mode));
}

Util::Util() {}

Util::~Util() {}

void Util::Uninstall() { zlog_fini(); }

int Util::Init() {

    const char *path = ZLOG_LOG_PAHT;

    // 检查路径
    if (!directory_exists(path)) {
        // 创建目录
        int status = mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);

        if (status == 0) {
            std::cout << "目录已成功创建\n";
        }
        else {
            std::cerr << "无法创建目录\n";
        }
    }

    rc = zlog_init("/etc/zlog.conf");
    if (rc) {
        printf("init failed\n");
        return ErrorInfo::ZLOG_INIT_FAIL;
    }

    log = zlog_get_category(ZLOG_CAT_NAME);
    if (!log) {
        printf("get cat fail\n");
        zlog_fini();
        return ErrorInfo::ZLOG_INIT_FAIL;
    }

    zlog_warn(log, "zlog init");
    zlog_w("log");
    return ErrorInfo::OK;
}

long long Util::TimeStamp() {
    struct timeval te;
    gettimeofday(&te, NULL); // 获取当前时间
    long long milliseconds =
        te.tv_sec * 1000LL +
        te.tv_usec / 1000; // 将秒转换为毫秒，并加上微秒的部分
    return milliseconds;
}

int Util::LoadConfiguration() {

    // 获取用户的 HOME 目录
    const char *homeDir = getenv("HOME");

    std::string filePath = homeDir;
    filePath.append("/.config/cluster-config.xml");
    zlog_w("读取配置文件: %s", filePath.c_str());
    if (!isFileExist(filePath)) {
        zlog_e("集群配置文件不存在");
        exit(-1);
    }

    // 创建一个属性树对象
    boost::property_tree::ptree pt;

    try {
        // 从XML文件中读取数据到属性树
        boost::property_tree::read_xml(filePath, pt);

        // 获取Cluster下的所有Node信息
        std::cout << "Cluster Nodes:" << std::endl;
        for (const auto &node : pt.get_child("document.Cluster")) {
            if (node.first == "Node") {
                int         id       = node.second.get<int>("<xmlattr>.id");
                std::string host     = node.second.get<std::string>("Host");
                int         port     = node.second.get<int>("Port");
                std::string password = node.second.get<std::string>("Password");
                Configuration::ClusterConf conf(id, host, port, password);

                Configuration::clusterConf.push_back(conf);
            }
        }

        std::cout << "cluster conf size: " << Configuration::clusterConf.size()
                  << std::endl;

        for (auto &conf : Configuration::clusterConf) {
            zlog_w("< ID: %d, Host: %s, Port: %d, Password: %s > ",
                   conf.ID,
                   conf.Host.c_str(),
                   conf.Port,
                   conf.Password.c_str());
        }

        // 输出Service下的HashKeyPrefix和StreamKey
        boost::property_tree::ptree service = pt.get_child("document.Service");

        std::string hashKeyPrefix = service.get<std::string>("HashKeyPrefix");
        //
        std::string streamKey = service.get<std::string>("StreamKey");

        int dataSyncUpdateInterval = service.get<int>("DataSyncUpdateInterval");

        if (dataSyncUpdateInterval < 5) {
            dataSyncUpdateInterval = 5;
        }

        int hashGroupCount = service.get<int>("HashGroupCount");
        if (hashGroupCount < 10) {
            hashGroupCount = 10;
        }

        int waitOverTime = service.get<int>("WaitOverTime");

        if (waitOverTime < 3) {
            waitOverTime = 3;
        }

        int dataExpireTime = service.get<int>("DataExpireTime");

        if (dataExpireTime < 5) {
            dataExpireTime = 5;
        }

        Configuration::DataTransferConf dataTransferConf(hashKeyPrefix,
                                                         streamKey,
                                                         dataSyncUpdateInterval,
                                                         hashGroupCount,
                                                         waitOverTime,
                                                         dataExpireTime);
        Configuration::dataConf.push_back(dataTransferConf);

        zlog_w("< HashKeyPrefix: %s > ",
               Configuration::dataConf.begin()->HashKeyPrefix.c_str());
        zlog_w("< StreamKey: %s > ",
               Configuration::dataConf.begin()->StreamKey.c_str());

        zlog_w("< UpdateInterval: %d > ",
               Configuration::dataConf.begin()->DataSyncUpdateInterval);

        zlog_w("< HashGroupCount: %d > ",
               Configuration::dataConf.begin()->HashGroupCount);

        if (Configuration::clusterConf.size() < 3) {
            zlog_e("配置集群Node数量少于3个,请完善配置文件");
            return ErrorInfo::CONFIG_FILE_FAIL;
        }

        auto iter = Configuration::dataConf.begin();

        if (iter->HashGroupCount == 0) {
            zlog_w("HashGroupCount 不可以是0");
            return ErrorInfo::CONFIG_FILE_FAIL;
        }

        if (iter->HashKeyPrefix == "") {
            zlog_w("< HashKeyPrefix 不可以为空 > ");
            return ErrorInfo::CONFIG_FILE_FAIL;
        }

        if (iter->StreamKey == "") {
            zlog_w("< StreamKey 不可以为空 > ");
            return ErrorInfo::CONFIG_FILE_FAIL;
        }
    }
    catch (const boost::property_tree::ptree_error &e) {
        zlog_e("%s", e.what());
        return ErrorInfo::CONFIG_FILE_NOT_FOUND;
    }

    return ErrorInfo::OK;
}

bool Util::isFileExist(const std::string &name) {
    if (FILE *file = fopen(name.c_str(), "r")) {
        fclose(file);
        return true;
    }
    else {
        return false;
    }
}

std::string Util::GetVarName(ModelNode *attr) {
    // TODO:

    util = GetInstance();
    std::string devName, varName, doName;

    // 如果Beh Mod类型直接返回备
    devName = util->GetDevName((ModelNode *)attr);
    doName  = util->GetDoName((ModelNode *)attr);
    if (doName.empty()) {
        return "";
    }
    varName = devName + "/" + doName;
    return varName;
}

std::string Util::GetDevName(ModelNode *node) {
    ModelNodeType type = ModelNode_getType(node);
    if (type != LogicalDeviceModelType) {
        return GetDevName(node->parent);
    }
    else {
        return node->name;
    }
}

std::string Util::GetDoName(ModelNode *node) {
    std::string name = ModelNode_getName(node);
    if (name == "Mod" || name == "Beh" || name == "Health") {
        return "";
    }
    ModelNodeType type = ModelNode_getType(node);
    if (type != DataObjectModelType) {
        return GetDoName(node->parent);
    }
    else {
        return node->name;
    }
}

std::shared_ptr<Util> Util::GetInstance() {
    if (util == nullptr) {
        util = std::make_shared<Util>();
    }
    return util;
}
